#include <winhack.h>
//#include <elasys_server.h>
#include <elapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <sysconfig.h>

#include "camplus.h"


#define DEFAULT_LCDWIDTH      240
#define DEFAULT_LCDHEIGHT     320

#define DEFAULT_SHOWBPP       16
#define DEFAULT_SHOWLAYER     2


void FrameDisplay::GetLCDSize()
{
    if (NOERROR != ConfigGetItemInt(L"LCDWidth",
       (int *)&(m_ulLCDWidth))) {
        m_ulLCDWidth = DEFAULT_LCDWIDTH;
    }

    if (NOERROR != ConfigGetItemInt(L"LCDHeight",
        (int *)&(m_ulLCDHeight))) {
        m_ulLCDHeight = DEFAULT_LCDHEIGHT;
    }
}

BOOL FrameDisplay::GetOverlayFormat(OverlayFormat *pOverlayFormat)
{
    IDeviceDriver *pDevice;

    ECode ec = _CSystem_FindRunningObject(
        L"device:display0", (IInterface **)&pDevice);
    if (FAILED(ec)) {
        printf("Error: Can't find Service: display, ec = 0x%08x! \
        file:%s. line:%d. \n",
        ec, __FILE__, __LINE__);
        return FALSE;
    }

    MemoryBuf_<sizeof(OverlayFormat)> ezbOutFbFmt;

    if (NOERROR != pDevice->Control(9, NULL_MEMORYBUF, &ezbOutFbFmt, NULL)) {
        printf("Error: Can't get overlay information, ec = 0x%08x! \
        file:%s. line:%d. \n",
        ec, __FILE__, __LINE__);
        pDevice->Release();
        return FALSE;
    }

    memcpy(pOverlayFormat, ezbOutFbFmt.GetPayload(), sizeof(OverlayFormat));

    pDevice->Release();
    return TRUE;
}

BOOL FrameDisplay::SetOverlayFormat(OverlayFormat *pOverlayFmtIn, OverlayFormat *pOverlayFmtOut)
{
    IDeviceDriver *pDevice;

    ECode ec = _CSystem_FindRunningObject(
        L"device:display0", (IInterface **)&pDevice);
    if (FAILED(ec)) {
        printf("Error: Can't find Service: display, ec = 0x%08x! \
        file:%s. line:%d. \n",
        ec, __FILE__, __LINE__);
        return FALSE;
    }

    MemoryBuf ezbInFbFmt((Byte *)pOverlayFmtIn, sizeof(OverlayFormat), sizeof(OverlayFormat));
    MemoryBuf ezbOutFbFmt((Byte *)pOverlayFmtOut, sizeof(OverlayFormat), sizeof(OverlayFormat));

    ezbInFbFmt.SetUsed(sizeof(OverlayFormat));

    ec = pDevice->Control(8, ezbInFbFmt, &ezbOutFbFmt, NULL);
    if (FAILED(ec)) {
        printf("Error: Can't set overlay information, ec = 0x%08x! \
        file:%s. line:%d. \n",
        ec, __FILE__, __LINE__);
        pDevice->Release();
        return FALSE;
    }

    pDevice->Release();

    return TRUE;
}

BOOL FrameDisplay::ChangeShowOverlay(unsigned long uWidth,
                                     unsigned long uHight)
{
    OverlayFormat OverlayFmt;

    OverlayFmt.Enable = TRUE;
    OverlayFmt.Color  = COLOR_YCbCr422; // MUST
    OverlayFmt.Layer  = DEFAULT_SHOWLAYER; // Use overlay2
    OverlayFmt.Bpp    = DEFAULT_SHOWBPP; // YCrCb422
    OverlayFmt.Width  = (int)uWidth;
    OverlayFmt.Height = (int)uHight;
    //The Preview resolution is always less than LCD screen
    OverlayFmt.PosX   = (m_ulLCDWidth - uWidth) / 2;
    OverlayFmt.PosY   = (m_ulLCDHeight - uHight) / 2;

    ECode ec = SetOverlayFormat(&OverlayFmt, &m_oCurrentShowFmt);
    if(FAILED(ec)){
        return FALSE;
    }

    return TRUE;
}

BOOL FrameDisplay::Initialize()
{

    GetLCDSize();

    if(!GetOverlayFormat(&m_oDefaultShowFmt)){
        printf("Error: camera FrameDisplay Initialize failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        return FALSE;
    }

    memcpy(&m_oCurrentShowFmt, &m_oDefaultShowFmt, sizeof(OverlayFormat));

    if(!m_Converter.Initialize()){
        printf("Error: camera FrameDisplay Initialize failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        return FALSE;
    }

    m_hOverlayLock = CreateMutexW(NULL, FALSE, NULL);
    if(NULL == m_hOverlayLock){
        printf("Error: camera FrameDisplay Initialize failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        m_Converter.Destroy();
        return FALSE;
    }

    return TRUE;
}

void FrameDisplay::Destroy()
{
    m_Converter.Destroy();

    if(NULL != m_hOverlayLock){
        CloseHandle(m_hOverlayLock);
    }
}

void  FrameDisplay::SetDigitalZoom(int zoom)
{
    m_Converter.SetDigitalZoom(zoom);
}

BOOL  FrameDisplay::SetSrcFormat(unsigned long SrcWidth,
                   unsigned long SrcHeight,
                   unsigned int  SrcPixelBs)
{
    WaitForSingleObject(m_hOverlayLock, (DWORD)INFINITE);
    if(!m_Converter.SetSrcFormat(SrcWidth, SrcHeight, SrcPixelBs)){
        ReleaseMutex(m_hOverlayLock);
        printf("Error: camera FrameDisplay SetSrcFormat failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        return FALSE;
    }

    ReleaseMutex(m_hOverlayLock);
    return TRUE;
}

BOOL  FrameDisplay::SetShowFormat(unsigned long uDesWidth,
                    unsigned long uDesHight)
{
    BOOL ret;
    unsigned long uWidth;
    unsigned long uHight;

    if(uDesWidth < DEFAULT_LCDWIDTH){
        uWidth = uDesWidth;
    } else {
        uWidth = DEFAULT_LCDWIDTH;
    }

    if(uDesHight < DEFAULT_LCDWIDTH){
        uHight = uDesHight;
    } else {
        uHight = DEFAULT_LCDHEIGHT;
    }

    WaitForSingleObject(m_hOverlayLock, (DWORD)INFINITE);
    ret = ChangeShowOverlay(uWidth, uHight);
    if(!ret){
        printf("Error: camera FrameDisplay SetShowFormat failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        ReleaseMutex(m_hOverlayLock);
        return FALSE;
    }

    ret = m_Converter.SetDesFormat(uWidth, uHight);
    ReleaseMutex(m_hOverlayLock);
    if(!ret){
        printf("Error: camera FrameDisplay SetShowFormat failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        return FALSE;
    }

    return TRUE;
}

BOOL FrameDisplay::ResetShowFormat()
{
    WaitForSingleObject(m_hOverlayLock, (DWORD)INFINITE);

    if(!SetOverlayFormat(&m_oDefaultShowFmt, &m_oDefaultShowFmt)){
        printf("Error: camera FrameDisplay SetOverlayFormat failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        ReleaseMutex(m_hOverlayLock);
        return FALSE;
    }

    memcpy(&m_oCurrentShowFmt, &m_oDefaultShowFmt, sizeof(OverlayFormat));

    BOOL ret = m_Converter.SetDesFormat(m_oCurrentShowFmt.Width,
                                        m_oCurrentShowFmt.Height);
    ReleaseMutex(m_hOverlayLock);
    if(!ret){
        printf("Error: camera FrameDisplay SetShowFormat failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        return FALSE;
    }

    return TRUE;
}

BOOL FrameDisplay::ShowFrame(void *pSrcBuf)
{
    YCbCrBufferInfo showInfo;
    BOOL ret;

    WaitForSingleObject(m_hOverlayLock, (DWORD)INFINITE);

    showInfo.pY = (BYTE *)(m_oCurrentShowFmt.pChannelFb[0]);
    showInfo.pCb = (BYTE *)(m_oCurrentShowFmt.pChannelFb[1]);
    showInfo.pCr = (BYTE *)(m_oCurrentShowFmt.pChannelFb[2]);

    ret = m_Converter.RGBTo422Normal((BYTE *)pSrcBuf, showInfo);

    ReleaseMutex(m_hOverlayLock);

    if(!ret){
        printf("Error: camera FrameDisplay ShowFrame failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        return FALSE;
    }

    return TRUE;
}


